let _Vue

export default class VueRouter {
  static install (Vue) {
    if (_Vue === Vue && VueRouter.install.installed) return

    _Vue = Vue
    VueRouter.install.installed = true

    _Vue.mixin({
      beforeCreate () {
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router
          this.$options.router.init()
        }
      }
    })
  }

  constructor (options) {
    this.options = options // 只实现 options.routes
    this.routeMap = {}
    // 是响应式的数据, 搜索 data.current, <router-link> <router-view> 组件中
    // https://cn.vuejs.org/v2/api/?#Vue-observable
    this.data = _Vue.observable({
      current: '/'
    })
  }

  createRouteMap () {
    this.options.routes.forEach(route => {
      this.routeMap[route.path] = route.component
    })
  }

  initComponents () {
    const self = this // this = vueRouter实例
    // <router-lint>
    _Vue.component('router-link', {
      props: {
        to: String
      },
      render (h) {
        return h(
          'a',
          {
            attrs: {
              href: this.to
            },
            on: {
              click: this.clickHandler
            }
          },
          [this.$slots.default]
        )
      },
      methods: {
        clickHandler (e) {
          // this = vm
          e.preventDefault()
          if (!self.options.mode || self.options.mode === 'hash') {
            // 改变 hash 会触发 hashchange事件
            window.location.hash = this.to
          } else if (self.options.mode === 'history') {
            history.pushState({}, '', this.to)
            this.$router.data.current = this.to
          }
        }
      }
    })

    _Vue.component('router-view', {
      render (h) {
        return h(self.routeMap[self.data.current])
      }
    })
  }

  initEvent () {
    window.addEventListener('popstate', () => {
      this.data.current = window.location.pathname
    })
    window.addEventListener('hashchange', () => {
      // 统一在 hashchange 中处理
      this.data.current = window.location.hash.slice(1)
    })
  }

  init () {
    this.createRouteMap()
    this.initComponents()
    this.initEvent()
  }
}
